package edu.pku.sei.transformation.testcase;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

import edu.pku.sei.bridge.mdabase.adapter.EMFXMILoader;
import edu.pku.sei.mdabase.basictypes.PrimitiveType;
import edu.pku.sei.mdabase.infrastructure.metamodel.MetaClass;
import edu.pku.sei.mdabase.infrastructure.metamodel.MetaReference;
import edu.pku.sei.mdabase.infrastructure.model.MModelGraph;
import edu.pku.sei.mdabase.infrastructure.runtime.Context;
import edu.pku.sei.queryscript.parser.ScriptParser;
import edu.pku.sei.transformation.main.MoTiFRunner;
import edu.pku.sei.transformation.mtparser.Ast;
import edu.pku.sei.transformation.pattern.TPatternEdge;
import edu.pku.sei.transformation.pattern.TPatternGraph;
import edu.pku.sei.transformation.pattern.TPatternNode;
import edu.pku.sei.transformation.semantics.TransformationController;
import edu.pku.sei.transformation.serialization.EMFXMISaver;
import edu.pku.sei.transformation.serialization.TransformationLoader;
import edu.pku.sei.transformation.structure.Key;
import edu.pku.sei.transformation.structure.PatternDomain;
import edu.pku.sei.transformation.structure.Rule;
import edu.pku.sei.transformation.structure.RuleBasedEnvironment;
import edu.pku.sei.transformation.structure.Trace;
import edu.pku.sei.transformation.structure.Transformation;
import edu.pku.sei.transformation.structure.TypedModel;
import edu.pku.sei.transformation.visitor.MTControllerVisitor;
import edu.pku.sei.transformation.visitor.MTScriptParser;

public class ModelSyncTestCase
{
	private String scriptContent;
	private String targetModelFile;
	private String src;
	public String getSrc()
	{
		return src;
	}

	public void setSrc(String src)
	{
		this.src = src;
	}

	public String getTar()
	{
		return tar;
	}

	public void setTar(String tar)
	{
		this.tar = tar;
	}

	private String tar;
	
	ModelSyncTestCase(String content)
	{
		scriptContent = content;
	}
	
	public String getContent()
	{
		return scriptContent;
	}
	
	public static void main (String args[]) throws IOException, ParserConfigurationException, SAXException
	{
		MoTiFRunner runner = new MoTiFRunner("C2JOnAS.trans", 
				"arc", 
				"sys", 
				"C2JOnAS\\BSide.xmi", 
				"C2JOnAS\\ASide.xmi", 
				"st.txt");
		runner.run();
	}
	
	private RuleBasedEnvironment env;
	private Context base;
	private Trace trace = new Trace();
	
	public RuleBasedEnvironment getEnv()
	{
		if (env == null)
			env = new RuleBasedEnvironment();
		return env;
	}
	
	public Context getBaseContext()
	{
		return base;
	}
	
	public Trace getTrace()
	{
		return trace;
	}
	
	public void init() throws ParserConfigurationException, SAXException, IOException
	{
		env = new RuleBasedEnvironment();
		base = new Context();
		TransformationLoader loader = new TransformationLoader();
		String transFilename = "C2JOnAS.trans";
		File file = new File(transFilename);
		Transformation trans;
		trans = loader.load(file);
		env.setTransformation(trans);
		for (Rule rule : trans.getOwnedRules())
		{
			env.registRule(rule.getName(), rule);
		}
		base.setEnvironment(env);
//		createKeys();
//		createRules();
		//TransformationCont
//		List<Domain> domains = new ArrayList<Domain>();
//		for (PatternDomain domain : trans.getRule("ClassToTable").getDomains())
//		{
//			domains.add((Domain)domain);
//		}
	}
	
	public void run(Ast ast)
	{
		MTControllerVisitor visitor = new MTControllerVisitor(getEnv(), getBaseContext(), getTrace());
		ast.accept(visitor);
		env.setMTVisitor(visitor);
		System.out.println("First visit done");
		//first visit done, semantics loaded
		
		String modename = "enforce";
		
		String ruleName = "Root2Root";
		TransformationController.instance.registVariable(getBaseContext(), env.getTransformation().getRule(ruleName));
		Object result = env.getMTVisitor().invokeSemantic(ruleName, null, modename);
		System.out.println("Rule " + ruleName + " has finished execution. Result = " + result);
		
		ruleName = "Component2EntityBean";
		TransformationController.instance.registVariable(getBaseContext(), env.getTransformation().getRule(ruleName));
		result = env.getMTVisitor().invokeSemantic(ruleName, null, modename);
		System.out.println("Rule " + ruleName + " has finished execution. Result = " + result);
		
		ruleName = "Component2StatefulSessionBean";
		TransformationController.instance.registVariable(getBaseContext(), env.getTransformation().getRule(ruleName));
		result = env.getMTVisitor().invokeSemantic(ruleName, null, modename);
		System.out.println("Rule " + ruleName + " has finished execution. Result = " + result);
		
		ruleName = "Component2StatelessSessionBean";
		TransformationController.instance.registVariable(getBaseContext(), env.getTransformation().getRule(ruleName));
		result = env.getMTVisitor().invokeSemantic(ruleName, null, modename);
		System.out.println("Rule " + ruleName + " has finished execution. Result = " + result);
		
		ruleName = "Component2WebModule";
		TransformationController.instance.registVariable(getBaseContext(), env.getTransformation().getRule(ruleName));
		result = env.getMTVisitor().invokeSemantic(ruleName, null, modename);
		System.out.println("Rule " + ruleName + " has finished execution. Result = " + result);
		
		ruleName = "Component2DataSource";
		TransformationController.instance.registVariable(getBaseContext(), env.getTransformation().getRule(ruleName));
		result = env.getMTVisitor().invokeSemantic(ruleName, null, modename);
		System.out.println("Rule " + ruleName + " has finished execution. Result = " + result);
		if (modename.equals("enforce"))
		{
			EMFXMISaver saver = new EMFXMISaver();
			MModelGraph model = env.getModelByTypedModel(env.getTransformation().getFormalParameter(getTar()));
			saver.save(model, targetModelFile);
		}
	}
	
	private void loadModels(String dir)
	{
		
		TypedModel sourceTypedModel = env.getTransformation().getFormalParameter(getSrc());
		TypedModel targetTypedModel = env.getTransformation().getFormalParameter(getTar());
		MModelGraph sourceModel = null, targetModel= null;
		if (dir.equals("A2B"))
		{
			EMFXMILoader srcloader = new EMFXMILoader("JOnAS");
			sourceModel = srcloader.load("C2JOnAS\\ASide.xmi");
			if (sourceModel == null)
				System.out.println("loading source model failed");
			sourceModel.setTypeGraph(sourceTypedModel.getType().getMetamodel());
			
			EMFXMILoader tarloader = new EMFXMILoader("C2");
			targetModelFile = "C2JOnAS\\BSide.xmi";
			targetModel = tarloader.load(targetModelFile);
			if (targetModel == null)
			{
				System.out.println("loading target model failed");
				targetModel = new MModelGraph();
			}
			targetModel.setTypeGraph(targetTypedModel.getType().getMetamodel());
		}
		
		else if (dir.equals("B2A"))
		{
			EMFXMILoader srcloader = new EMFXMILoader("C2");
			sourceModel = srcloader.load("C2JOnAS\\BSide.xmi");
			if (sourceModel == null)
				System.out.println("loading source model failed");
			sourceModel.setTypeGraph(sourceTypedModel.getType().getMetamodel());
			
			EMFXMILoader tarloader = new EMFXMILoader("JOnAS");
			targetModelFile = "C2JOnAS\\ASide.xmi";
			targetModel = tarloader.load(targetModelFile);
			if (targetModel == null)
			{
				System.out.println("loading target model failed");
				targetModel = new MModelGraph();
			}
			targetModel.setTypeGraph(targetTypedModel.getType().getMetamodel());
		}
		
//		List<TypedModel> tms = new ArrayList<TypedModel>();
//		tms.add(sourceTypedModel);
//		tms.add(targetTypedModel);
//		env.getTransformation().setFormalParameters(tms);
		
		env.addTargetmodel(targetTypedModel);
		env.registerModel(sourceTypedModel, sourceModel);
		env.registerModel(targetTypedModel, targetModel);
	}
	
}
